{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Callisto tket framework\n", "\n", "The tket framework is a quantum software framework primarily used for the development and execution of quantum algorithms (quantum circuits). It is designed to be platform-agnostic software, and there are a lot of extensions available which allow tket to interface with backends from a range of providers ( see tket extension ).\n", "\n", "Due to its popularity and the broad amount of available backends using this framework, we wrote an extension to tket that enables a user to communicate with the C12 emulator Callisto . The backend name is `CallistoBackend`.\n", "\n", "We need to create a circuit using the `Circuit` class to run a quantum algorithm." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2024-10-08T14:54:52.019991Z", "start_time": "2024-10-08T14:54:51.906497Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[X q[0];, CX q[0], q[1];]\n" ] } ], "source": [ "from pytket import Circuit\n", "\n", "circuit = Circuit(2)\n", "circuit.X(0)\n", "circuit.CX(0, 1)\n", "\n", "print(circuit.get_commands())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Internally all circuits in the pytket framework are represented as directed acyclic graphs (DAG). Using ptyket util package it is possible to see the corresponding DAG of the chosen circuit." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A classical model for quantum computing is a model where the main program is run on the host computer, which occasionally sends off jobs to the quantum computer and retrieves the results. A backend represents a connection to some instance, either quantum hardware or an emulator. It presents a uniform interface for submitting circuits to be processed and retrieving the results. The main goal of this approach is to promote the development of platform-independent software, helping the code that the developers write to be more future-proof.\n", "\n", "Using tket's abstract class, `Backend,` it is possible to set different characteristics of a device that it should represent. The main properties that a backend need to implement are:\n", "\n", "1. The restrictions that are specific to specific quantum devices. Different constraints are encoded using the predicates, which are essentially a boolean property of a circuit that must return True to run the circuit on the target machine.\n", "\n", "2. Sending a circuit to the target device and examining the results. This process can be accomplished by calling `Backend.process_circuit()` or `Backend.process_circuits()` methods. These methods will send a circuit for execution and return an instance of `ResultHandle` as a result of their execution. The `ResultHandle` is a unique identifier that can be used to retrieve the actual results once the job has finished.\n", "\n", "3. Retrieval of the results. Obtaining the results of a successfully run job\n", " is done using the `Backend.get_result()` method, which returns an instance of `BackendResult` class. The class `BackendResult` has methods that can be useful for obtaining different pieces of information about the job that has been run. These methods are:\n", "`get_state()` - get the state vector\n", "`get_shots()` - get the shots. The shots are returned as a 2D array of the result for each shot.\n", "`get_counts()` - get the counts (it is obtained from the shots directly)\n", "`get_density_matrix()` - get the density matrix of the job.\n", "\n", "\n", "To implement the C12 emulator Callisto, we have developed `CallistoBackend` class with all the above options incorporated." ] }, { "cell_type": "code", "execution_count": 2, "outputs": [], "source": [ "import os\n", "os.environ[\"C12_TOKEN\"] = \"08071c09-4131-4369-ae5d-76be96a8cd86\"\n", "os.environ[\"C12_HOST_URL\"]= \"api.dev-simulator.c12qe.net\"" ], "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2024-10-08T14:55:11.492912Z", "start_time": "2024-10-08T14:55:11.490014Z" } } }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2024-10-08T14:55:17.168060Z", "start_time": "2024-10-08T14:55:15.127487Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "('0b022428-9ae3-4190-9129-3f4743905208',)\n" ] } ], "source": [ "import os\n", "from c12_callisto_clients.pytket.extensions.callisto import CallistoBackend\n", "\n", "access_token = os.getenv(\"C12_TOKEN\") # Token that is obtained for allowing the access to the system\n", "backend_name = \"c12sim-iswap\"\n", "\n", "# create callisto backend instance\n", "callisto = CallistoBackend(backend_name, token=access_token, verbose=False)\n", "\n", "# Get the ResultHandle instance\n", "handle = callisto.process_circuit(circuit, n_shots=1024)\n", "print(handle)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2024-10-08T14:56:11.741719Z", "start_time": "2024-10-08T14:55:19.552613Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CircuitStatus(status=, message='', error_detail=None, completed_time=None, queued_time=None, submitted_time=None, running_time=None, cancelled_time=None, error_time=None, queue_position=None)\n", "[[1 1]\n", " [1 1]\n", " [1 1]\n", " ...\n", " [1 1]\n", " [1 1]\n", " [1 1]]\n", "Counter({(np.uint8(1), np.uint8(1)): np.int64(1024)})\n" ] } ], "source": [ "job_uuid = handle[0]\n", "\n", "# Get BackendResult instance\n", "job_result = callisto.get_result(handle)\n", "\n", "\n", "print(callisto.circuit_status(handle)) # Get the status of the circuit\n", "print(job_result.get_shots())\n", "print(job_result.get_counts())" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2024-10-08T14:57:48.915299Z", "start_time": "2024-10-08T14:57:48.615372Z" } }, "outputs": [ { "ename": "CircuitNotValidError", "evalue": "Circuit with index 0 in submitted does not satisfy MaxNQubitsPredicate(13) (try compiling with backend.get_compiled_circuits first).", "output_type": "error", "traceback": [ "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", "\u001B[0;31mCircuitNotValidError\u001B[0m Traceback (most recent call last)", "Cell \u001B[0;32mIn[5], line 6\u001B[0m\n\u001B[1;32m 3\u001B[0m circuit2\u001B[38;5;241m.\u001B[39mX(n)\n\u001B[1;32m 4\u001B[0m circuit2\u001B[38;5;241m.\u001B[39mCX(\u001B[38;5;241m0\u001B[39m, n)\n\u001B[0;32m----> 6\u001B[0m handle2 \u001B[38;5;241m=\u001B[39m \u001B[43mcallisto\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mprocess_circuit\u001B[49m\u001B[43m(\u001B[49m\u001B[43mcircuit2\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mn_shots\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;241;43m1024\u001B[39;49m\u001B[43m)\u001B[49m\n\u001B[1;32m 8\u001B[0m \u001B[38;5;66;03m# This should fail due to MaxNQubitsPredicate which controls the number of qubits that can be run on the emulator\u001B[39;00m\n", "File \u001B[0;32m~/Desktop/Projects/simulator/C12QEsimulator/src/c12_callisto_clients/pytket/extensions/callisto/backends/callisto.py:321\u001B[0m, in \u001B[0;36mCallistoBackend.process_circuit\u001B[0;34m(self, circuit, n_shots, valid_check, **kwargs)\u001B[0m\n\u001B[1;32m 317\u001B[0m \u001B[38;5;250m\u001B[39m\u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[1;32m 318\u001B[0m \u001B[38;5;124;03mRun a single circuit.\u001B[39;00m\n\u001B[1;32m 319\u001B[0m \u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[1;32m 320\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m valid_check:\n\u001B[0;32m--> 321\u001B[0m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_check_all_circuits\u001B[49m\u001B[43m(\u001B[49m\u001B[43m[\u001B[49m\u001B[43mcircuit\u001B[49m\u001B[43m]\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 323\u001B[0m n_shots \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m1024\u001B[39m \u001B[38;5;28;01mif\u001B[39;00m n_shots \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m \u001B[38;5;28;01melse\u001B[39;00m n_shots\n\u001B[1;32m 324\u001B[0m result_type \u001B[38;5;241m=\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mcounts,statevector,density_matrix\u001B[39m\u001B[38;5;124m\"\u001B[39m\n", "File \u001B[0;32m/opt/anaconda3/envs/c12_callisto_clients/lib/python3.10/site-packages/pytket/backends/backend.py:126\u001B[0m, in \u001B[0;36mBackend._check_all_circuits\u001B[0;34m(self, circuits, nomeasure_warn)\u001B[0m\n\u001B[1;32m 120\u001B[0m errors \u001B[38;5;241m=\u001B[39m (\n\u001B[1;32m 121\u001B[0m CircuitNotValidError(i, \u001B[38;5;28mrepr\u001B[39m(pred))\n\u001B[1;32m 122\u001B[0m \u001B[38;5;28;01mfor\u001B[39;00m pred \u001B[38;5;129;01min\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mrequired_predicates\n\u001B[1;32m 123\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m pred\u001B[38;5;241m.\u001B[39mverify(circ)\n\u001B[1;32m 124\u001B[0m )\n\u001B[1;32m 125\u001B[0m \u001B[38;5;28;01mfor\u001B[39;00m error \u001B[38;5;129;01min\u001B[39;00m errors:\n\u001B[0;32m--> 126\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m error\n\u001B[1;32m 127\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m nomeasure_warn:\n\u001B[1;32m 128\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m circ\u001B[38;5;241m.\u001B[39mn_gates_of_type(OpType\u001B[38;5;241m.\u001B[39mMeasure) \u001B[38;5;241m<\u001B[39m \u001B[38;5;241m1\u001B[39m:\n", "\u001B[0;31mCircuitNotValidError\u001B[0m: Circuit with index 0 in submitted does not satisfy MaxNQubitsPredicate(13) (try compiling with backend.get_compiled_circuits first)." ] } ], "source": [ "circuit2 = Circuit(20)\n", "for n in range(1, 20):\n", " circuit2.X(n)\n", " circuit2.CX(0, n)\n", "\n", "handle2 = callisto.process_circuit(circuit2, n_shots=1024)\n", "\n", "# This should fail due to MaxNQubitsPredicate which controls the number of qubits that can be run on the emulator" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.13" } }, "nbformat": 4, "nbformat_minor": 4 }